// 导入 threejs
import * as THREE from 'three'
// 导入轨道控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
// 导入lil.gui
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js'
// 导入 hdr 加载器. 专门用来加载hdr图的
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js'

// 创建场景
const scene= new THREE.Scene()

// 创建相机
const camera = new THREE.PerspectiveCamera(
  45,  // 视角
  window.innerWidth / window.innerHeight,
  0.1,  // 近平面
  1000   // 远平面
)

// 创建渲染器
const renderer = new THREE.WebGLRenderer()
renderer.setSize(window.innerWidth, window.innerHeight)   // 整屏渲染，canvas为基础

// 将画布添加到页面标签里
document.body.appendChild(renderer.domElement)

// 添加世界坐标辅助器，x,y,z轴的辅助线
const axesHelper = new THREE.AxesHelper(5)   // 并设置线段的长度为5
// 添加到场景当中
scene.add(axesHelper)

// 设置相机位置
// camera.position.z = 5   // 设置在哪个轴， x, y, z 这里设置z轴
// camera.lookAt(0, 0, 0)    // 设置相机看向什么位置，看向原点位置

// 为了看到z轴的线，调整相机位置
camera.position.z = 5   
camera.position.x = 3
camera.position.y = 2
camera.lookAt(0, 0, 0)  

// 添加轨道控制器， 先在上面导入
const controls = new OrbitControls(camera, renderer.domElement)   // renderer.domElement这个表示监听的元素是 canvas 元素， 渲染的标签
// const controls = new OrbitControls(camera, document.body)   // 监听body
// 设置带阻尼的惯性，阻尼感
controls.enableDamping = true         // 开启
// 设置阻尼系数
// controls.dampingFactor = 0.01          // 越小阻尼感越大
controls.dampingFactor = 0.5
// controls.autoRotate = true         // 自转，自动绕着目标旋转， 开启这个必须要使用 controls方法

// 做一个渲染函数， 不断渲染
function animate() {
  controls.update()    // 渲染的时候也要每次更新控制器
  requestAnimationFrame(animate)       // 相当于定时器，不断调用，一直渲染
  // 旋转功能
  // cube.rotation.x += 0.01
  // cube.rotation.y += 0.01
  // 渲染
  renderer.render(scene, camera)
}
animate()

// 监听窗口变化
window.addEventListener("resize", () => {
  // 重置渲染器宽高比
  renderer.setSize(window.innerWidth, window.innerHeight)
  // 重置相机宽高比
  camera.aspect = window.innerWidth / window.innerHeight
  // 更新相机投影矩阵 ， 一定要加
  camera.updateProjectionMatrix()
})


// 创建纹理加载器
let textureLoader = new THREE.TextureLoader()
// 各种贴图是建模师给的
// 加载纹理（贴图）
let texture = textureLoader.load("/picture/13.png")      // 13.jpg、14.jpg是背景白色   13.png、14.png是背景透明的
// 设置纹理的颜色空间
// texture.colorSpace = THREE.SRGBColorSpace          // 改成 sRGB的(颜色会深点)， 这块涉及到色彩空间的问题   
// texture.colorSpace = THREE.LinearSRGBColorSpace        // 设置线性的 linear
texture.colorSpace = THREE.NoColorSpace
/*
  linear: 按发射光强度均匀分布的灰度条
  sRGB: 在感知光强度方面均匀分布的灰度条
*/

// 加载ao贴图，（是指环境遮挡贴图）
let aoMap = textureLoader.load("/picture/14.png")

// 加载透明度贴图，黑白图
let alphaMap = textureLoader.load("/picture/11.jpeg")

// 加载光照贴图
let lightMap = textureLoader.load("/picture/15.jpg")

// 高光贴图  （让物体更逼真）
let specularMap = textureLoader.load("/picture/16.jpg")

// rgbeLoader  加载hdr贴图
let rgbeLoader = new RGBELoader()
// rgbeLoader.load("/picture/u.hdr", (envMap) => {  // 有一个回调函数，返回的就是加载后的纹理了
rgbeLoader.load("/picture/n.hdr", (envMap) => { 
  // 设置球形贴图
  envMap.mapping = THREE.EquirectangularReflectionMapping
  // 直接设置环境贴图，作为整个场景的背景
  scene.background = envMap
  // 给平面设置环境贴图，效果为反光
  planeMaterial.envMap = envMap
})

// 创建基础平面图
let planeGeometry = new THREE.PlaneGeometry(1, 1)
// 创建材质
let planeMaterial = new THREE.MeshBasicMaterial({
  color: 0xffffff,
  side: THREE.DoubleSide,
  map: texture,                       // 贴图，将纹理贴图放到材质 map 属性里
  transparent: true,          // 允许透明（设置属性为true后 图片上有透明的部分是能变透明的）
  aoMap: aoMap,                  // 环境遮挡贴图， ao贴图
  aoMapIntensity: 1,            // 环境遮挡贴图的遮挡强度, 不设置默认是1
  alphaMap: alphaMap,            // 透明度贴图
  lightMap: lightMap,            // 光照贴图
  specularMap: specularMap,      // 设置高光贴图， 让明亮的地方反射更清楚
  reflectivity: 0.5,              // 设置反射强度
})
// 单独设置也可以
// planeMaterial.map = texture

let plane = new THREE.Mesh(planeGeometry, planeMaterial)
scene.add(plane)


// 创建GUI
const gui = new GUI()
// gui.add(debugEvent, "Fullscreen")        // 会在界面上自动创建调试的按钮
gui.add(planeMaterial, "aoMapIntensity").min(0).max(2).name("aop强度")  //   aoMapIntensity是用来设置环境遮挡贴图的遮挡强度的
gui.add(texture, "colorSpace", {
  sRGB: THREE.SRGBColorSpace,
  Linear: THREE.LinearSRGBColorSpace,
}).onChange(() => {
  // 一定要监听并告诉纹理图，需要更新
  texture.needsUpdate = true
})